#pragma once
#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;

using func_t = std::function<std::string(const std::string& , InetAddr& )>;

static const int defaultlistenfd = -1;
static const int backlog = 8;

class TcpServer : public NoCopy{
public:
	TcpServer(func_t func, uint16_t port)
		:_func(func), _isrunning(false), _port(port), _listensockfd(defaultlistenfd)
	{}
	
	void Service(int sockfd, InetAddr& peer){
		char buffer[1024];
		while(true){
			int n = read(sockfd, buffer, sizeof(buffer) - 1);
			if(n > 0){
				buffer[n] = 0;
				LOG(LogLevel::DEBUG) << peer.StringAddr() << "# " << buffer;
				std::string echo_string = _func(buffer, peer);
				
				write(sockfd, echo_string.c_str(), echo_string.size());
			}
			else if(n == 0){
				LOG(LogLevel::DEBUG) << peer.StringAddr() << "退出了...";
				close(sockfd);
				break;
			}
			else {
				LOG(LogLevel::DEBUG) << peer.StringAddr() << "异常...";
				close(sockfd);
				break;
			}
		}
	}
	
	void Init(){
		_listensockfd = socket(AF_INET, SOCK_STREAM, 0);
		if(_listensockfd < 0){
			LOG(LogLevel::FATAL) << "socket error...";
			exit(SOCKET_ERR);
		}
		LOG(LogLevel::INFO) << "socket success: " << _listensockfd;
		
		InetAddr local(_port);
		
		int n = bind(_listensockfd, local.NetAddrPtr(), local.NetAddrLen());
		if(n < 0){
			LOG(LogLevel::FATAL) << "bind error";
			exit(BIND_ERR);
		}
		LOG(LogLevel::INFO) << "bind success: " << _listensockfd;
		
		n = listen(_listensockfd, backlog);
		if(n < 0){
			LOG(LogLevel::FATAL) << "listen error...";
			exit(LISTEN_ERR);
		}
		LOG(LogLevel::INFO) << "listen success: " << _listensockfd;
	}
	
	void Run(){
		_isrunning = true;
		while(true){
			struct sockaddr_in peer;
			socklen_t len = sizeof(peer);
			int sockfd = accept(_listensockfd, CONV(peer), &len);
			if(sockfd < 0){
				LOG(LogLevel::FATAL) << "accept error";
				continue;
			}
			
			InetAddr addr(peer);
			LOG(LogLevel::INFO) << "accept success, peer addr" << addr.StringAddr();
			
			Service(sockfd, addr);
		}
		_isrunning = false;
	}

private:
	int _listensockfd;
	func_t _func;
	bool _isrunning;
	uint16_t _port;
};































